﻿using Kylin.Wiki.Core.Enum;
using Kylin.Wiki.Core.Extensions; 
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace Kylin.Wiki.Repository
{
    public  class Repository<T> : IRepository<T> where T : class,new()
    {
        private readonly OnlyOfficeContext _dbContext ; 
         
        public Repository(OnlyOfficeContext dbContext)
        {
            _dbContext = dbContext;
        } 

        private DbSet<T> DBSet
        {
            get { return _dbContext.Set<T>(); }
        }

        #region 简单查询
        /// <summary>
        /// 按ID查询
        /// </summary>
        /// <param name="objId">实体ID</param>
        /// <returns></returns>
        public T FindFirst(Expression<Func<T, bool>> where)
        {
            return _dbContext.Set<T>().AsNoTracking().Where(where).FirstOrDefault();

        }

        /// <summary>
        /// 异步按条件查询
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public Task<T> FindFirstAsync(Expression<Func<T, bool>> where)
        {
            return _dbContext.Set<T>().AsNoTracking().Where(where).FirstOrDefaultAsync();
        }

        /// <summary>
        /// 根据条件查询数据是否存在
        /// </summary>
        /// <param name="where">条件表达式树</param>
        /// <returns></returns>
        public bool Exists(Expression<Func<T, bool>> where)
        {
            return DBSet.AsNoTracking().Any(where);
        }

        /// <summary>
        /// 异步根据条件查询数据是否存在
        /// </summary>
        /// <param name="where">条件表达式树</param>
        /// <returns></returns>
        public Task<bool> ExistsAsync(Expression<Func<T, bool>> where)
        {
            return DBSet.AsNoTracking().AnyAsync(where);
        }

        /// <summary>
        /// 通过条件查询数据
        /// </summary>
        /// <param name="objIds"></param>
        /// <returns></returns>
        public List<T> Find(Expression<Func<T, bool>> where)
        {
            return _dbContext.Set<T>().Where(where).AsNoTracking().ToList();
        }
         
        /// <summary>
        /// 异步通过条件查询数据
        /// </summary>
        /// <param name="objIds"></param>
        /// <returns></returns>
        public Task<List<T>> FindAsync(Expression<Func<T, bool>> where)
        {
            return _dbContext.Set<T>().AsNoTracking().Where(where).ToListAsync();
        }

        /// <summary>
        /// 通过条件查询数据
        /// </summary>
        /// <param name="predicate">where条件</param>
        /// <param name="orderBy">排序字段,数据格式如:
        ///  orderBy = x => new Dictionary<object, bool>() {
        ///          { x.BalconyName,QueryOrderBy.Asc},
        ///          { x.TranCorpCode1,QueryOrderBy.Desc}
        ///         };
        /// </param>
        /// <returns></returns> 
        public IQueryable<T> FindAsIQueryable(Expression<Func<T, bool>> predicate, Expression<Func<T, Dictionary<object, QueryOrderBy>>> orderBy = null)
        {
            return _dbContext.Set<T>().AsNoTracking().Where(predicate).OrderBy(orderBy);
        }

        /// <summary>
        /// 异步通过条件查询数据
        /// </summary>
        /// <param name="predicate"></param>
        /// <param name="orderBy"></param>
        /// <returns></returns>
        public Task<List<T>> Find(Expression<Func<T, bool>> predicate, Expression<Func<T, Dictionary<object, QueryOrderBy>>> orderBy = null)
        {
            return _dbContext.Set<T>().AsNoTracking().Where(predicate).OrderBy(orderBy).ToListAsync();
        }

        /// <summary>
        /// 通过条件查询数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="predicate">查询条件</param>
        /// <param name="selector">返回类型如:Find(x => x.UserName == loginInfo.userName, p => new { uname = p.UserName });</param>
        /// <returns></returns>
        public List<T> Find<TReulst>(Expression<Func<T, bool>> predicate, Expression<Func<T, T>> selector)
        {
            return DBSet.Where(predicate).AsNoTracking().Select(selector).ToList();
        }

        /// <summary>
        /// 异步通过条件查询数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="predicate">查询条件</param>
        /// <param name="selector">返回类型如:Find(x => x.UserName == loginInfo.userName, p => new { uname = p.UserName });</param>
        /// <returns></returns>
        public Task<List<T>> FindAsync<TResult>(Expression<Func<T, bool>> predicate, Expression<Func<T, T>> selector)
        {
            return DBSet.Where(predicate).AsNoTracking().Select(selector).ToListAsync();
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="pageIndex"></param>
        /// <param name="pagesize"></param>
        /// <param name="rowcount"></param>
        /// <param name="predicate"></param>
        /// <param name="orderBy"></param>
        /// <param name="returnRowCount"></param>
        /// <returns></returns>
        public List<T> QueryablePage(int pageIndex, int pagesize, out int rowcount, Expression<Func<T, bool>> predicate, Dictionary<string, QueryOrderBy> orderBy, bool returnRowCount = true)
        {
            pageIndex = pageIndex <= 0 ? 1 : pageIndex;
            pagesize = pagesize <= 0 ? 10 : pagesize;
            if (predicate == null)
            {
                predicate = x => 1 == 1;
            }
            rowcount = returnRowCount ? DBSet.AsNoTracking().Count(predicate) : 0;
            return DBSet.AsNoTracking().Where(predicate)
                .GetIQueryableOrderBy(orderBy)
                .Skip((pageIndex - 1) * pagesize)
                .Take(pagesize).ToList();
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="pageIndex"></param>
        /// <param name="pagesize"></param>
        /// <param name="rowcount"></param>
        /// <param name="predicate"></param>
        /// <param name="orderBySelector"></param>
        /// <param name="selectorResult"></param>
        /// <param name="returnRowCount"></param>
        /// <returns></returns>
        public List<T> QueryByPage<TResult>(int pageIndex, int pagesize, out int rowcount, Expression<Func<T, bool>> predicate, Expression<Func<T, Dictionary<object, QueryOrderBy>>> orderBySelector, Expression<Func<T, T>> selectorResult, bool returnRowCount = true)
        {
            pageIndex = pageIndex <= 0 ? 1 : pageIndex;
            pagesize = pagesize <= 0 ? 10 : pagesize;
            if (predicate == null)
            {
                predicate = x => 1 == 1;
            }
            var _db = _dbContext.Set<T>().AsNoTracking();
            rowcount = returnRowCount ? _db.AsNoTracking().Count(predicate) : 0;
            var queryable = _dbContext.Set<T>().Where(predicate)
                .GetIQueryableOrderBy(orderBySelector.GetExpressionToDic())
                .Skip((pageIndex - 1) * pagesize)
                .Take(pagesize);
            return queryable.Select(selectorResult).ToList();
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="pageIndex"></param>
        /// <param name="pagesize"></param>
        /// <param name="predicate"></param>
        /// <param name="orderBy"></param>
        /// <param name="selectorResult"></param>
        /// <returns></returns>
        public List<T> QueryByPage<TResult>(int pageIndex, int pagesize, Expression<Func<T, bool>> predicate, Expression<Func<T, Dictionary<object, QueryOrderBy>>> orderBy, Expression<Func<T, T>> selectorResult = null)
        {
            pageIndex = pageIndex <= 0 ? 1 : pageIndex;
            pagesize = pagesize <= 0 ? 10 : pagesize;
            if (predicate == null)
            {
                predicate = x => 1 == 1;
            }
            var _db = _dbContext.Set<T>().AsNoTracking();
            return _dbContext.Set<T>().Where(predicate)
                .GetIQueryableOrderBy(orderBy.GetExpressionToDic())
                .Skip((pageIndex - 1) * pagesize)
                .Take(pagesize).Select(selectorResult).ToList();
        }

        #endregion

        #region 添加操作
        /// <summary>
        /// 添加数据
        /// </summary>
        /// <param name="entities"></param>
        /// <param name="SaveChanges"></param>
        public int Add(T entities, bool SaveChanges = false)
        {
            int result = 0;
            DBSet.AddRange(entities);
            if (SaveChanges)
                return _dbContext.SaveChanges();
            return entities.GetInt();

        }

        /// <summary>
        /// 批量添加
        /// </summary>
        /// <param name="entities"></param>
        /// <param name="SaveChanges"></param>
        public int AddRange(IEnumerable<T> entities, bool SaveChanges = false)
        {
            _dbContext.Set<T>().AddRange(entities);
            if (SaveChanges)
                return _dbContext.SaveChanges();
            return 0;
        }
        #endregion

        #region 删除操作 

        /// <summary>
        /// 按Entity删除数据
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public int Delete(T model, bool saveChanges = false)
        {
            DBSet.Remove(model);
            if (saveChanges)
            {
                return _dbContext.SaveChanges();
            }
            return 0;
        } 
         

        #endregion

        #region 修改操作

        /// <summary>
        /// 根据Entity修改数据（注意会修改所有字段值）
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public int Update(T entity, bool saveChanges = false)
        {
            DBSet.Update(entity);
            int count = 0;
            if (saveChanges)
                count = _dbContext.SaveChanges();
            return count;
        }

        /// <summary>
        /// 根据Entity修改数据（指定字段）
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="updatedProperties"></param>
        /// <param name="saveChanges"></param>
        /// <returns></returns>
        public int Update(T entity, Expression<Func<T, object>>[] updatedProperties,bool saveChanges = false)
        {
            int result = 0;
            DBSet.Attach(entity);
            if (updatedProperties.Any())
            {
                foreach (var property in updatedProperties)
                {
                    _dbContext.Entry<T>(entity).Property(property).IsModified = true;
                }
            }
            if (saveChanges)
                result = _dbContext.SaveChanges(); 

            return result; 
        }
        /// <summary>
        /// 批量修改数据（注意会修改所有字段值）
        /// </summary>
        /// <param name="entities"></param>
        /// <returns></returns>
        public int Update(List<T> entities, bool saveChanges = false)
        {
            DBSet.UpdateRange(entities);
            int count = 0;
            if (saveChanges)
                count = _dbContext.SaveChanges();
            return count;
        }
          
        #endregion 
    }
}
